#include "pch.h"
#include "Unit.h"
#include "UnitDerive.h"
#include "RendererEngine.h"
#include "ResourceManager.h"
#include "Vector.h"
#include "Texture.h"
#include "LightActor.h"

namespace mini
{
	CUnit::CUnit()
//		:mUnitFlag(unKnow)
	{
		mstartItem = mProperty.end();
		++mUnitID;
	}

	CUnit::~CUnit()
	{

	}

	void CUnit::onInitialise()
	{

	}

	void CUnit::update(float fDeltaTime)
	{

	}

	void CUnit::onUninitialise()
	{

	}

	void CUnit::setUnitFile(const std::string& strFileName)
	{
		mstrFileName = strFileName;
	}

	Property& CUnit::getProperty(UINT32 uIndex)
	{
		if (uIndex < mProperty.size())
		{
			return *(mProperty[uIndex]);
		}
		else
		{
			return (*(Property*)(0));
		}
	}

	Property& CUnit::getProperty(const std::string& strName)
	{
		auto item = mstrProperty.find(strName);
		if (item != mstrProperty.end())
		{
			return item->second;
		}
		else
		{
			return (*(Property*)(0));
		};
	}


	Property* CUnit::getPropertyFirst()
	{
		if (mProperty.size() > 0)
		{
			mstartItem = mProperty.begin();
			Property* pTempProperty = (*mstartItem);
			++mstartItem;
			return pTempProperty;
		}
		else
		{
			return nullptr;
		}
	}

	Property* CUnit::getPropertyNext()
	{
		if (mProperty.size() > 0)
		{
			if (mstartItem != mProperty.end())
			{
				Property* pTempProperty = (*mstartItem);
				++mstartItem;
				return pTempProperty;
			}
		}
		return nullptr;
	}

	UINT32 CUnit::getUnitID()
	{
		return mUnitID;
	}

	Property* CUnit::RegisterProperty(std::string strName, void* pData, PropertyDataType datatype, UINT32 flag, std::function<void()> func)
	{
		if (mstrProperty.find(strName) == mstrProperty.end())
		{
			UINT32 size = mProperty.size();
			mstrProperty[strName] = Property(size, strName, pData, datatype, flag, func);
			mProperty.push_back(&mstrProperty[strName]);
		}
		else
		{
			UINT32 nIndex = mstrProperty[strName].nIndex;
			mstrProperty[strName] = Property(nIndex, strName, pData, datatype, flag, func);
		}
		return &mstrProperty[strName];
	}



	void CUnit::exportPropertyToEditor()
	{

	}

	void CUnit::updateUnitProperty(Property* pProperty)
	{

	}

	void CUnit::updateMaterial()
	{

	}

	//////////////////////////////////////////////////////////////////////////
	CPostRendererUnit::CPostRendererUnit()
		: mpPostRender(nullptr)
	{
//		mUnitFlag = (UnitEnum::render | UnitEnum::client | UnitEnum::postrender);
	}

	CPostRendererUnit::~CPostRendererUnit()
	{
		SafeRelease(mpPostRender);
	}

	void CPostRendererUnit::updateSpace()
	{

	}

	//////////////////////////////////////////////////////////////////////////
	CWndUnit::CWndUnit()
		: mpWnd(nullptr)
	{
//		mUnitFlag = (UnitEnum::render | UnitEnum::client | UnitEnum::wnd);
	}

	CWndUnit::~CWndUnit()
	{
		SafeRelease(mpWnd);
	}

	void CWndUnit::onInitialise()
	{
		SafeRelease(mpWnd);
		CResourceBase* pResourceBase = CResourceManager::getSinglePtr()->findResource(mstrFileName);
		if (pResourceBase == nullptr)
		{
			mpWnd = dynamic_cast<ui::CWnd*>(CResourceManager::getSinglePtr()->createResource(mstrFileName, Wnd));
		}
		else
		{
			mpWnd = dynamic_cast<ui::CWnd*>(pResourceBase);
			mpWnd->AddRef();
		}
		Property* pProperty = RegisterProperty("Wnd", mpWnd, _ADDRESS, Logic, nullptr);
	}

	void CWndUnit::onUninitialise()
	{

	}

	void CWndUnit::update(float fDeltaTime)
	{
		if (mbDirty && mpWnd)
		{

		}
	}

	void CWndUnit::updateUnitProperty(Property* pProperty)
	{
	}

	void CWndUnit::updateSpace()
	{

	}

	ui::CWnd* CWndUnit::getWnd()
	{
		return mpWnd;
	}


	//////////////////////////////////////////////////////////////////////////
	CMeshUnit::CMeshUnit()
		: mpMesh(nullptr)
		, mpMaterialUnit(nullptr)
	{
	//	mUnitFlag = (UnitEnum::render | UnitEnum::client | UnitEnum::mesh);
		D3DXMatrixIdentity(&mWorldMatrix);
		D3DXMatrixIdentity(&mScaleMatrix);
		D3DXMatrixIdentity(&mPositionMatrix);
		D3DXMatrixIdentity(&mRotationMatrix[0]);
		D3DXMatrixIdentity(&mRotationMatrix[1]);
		D3DXMatrixIdentity(&mRotationMatrix[2]);

		mPosition = CVector(0, 0, 0);
		mScale = CVector(1, 1, 1);
		mRotation = CVector(0, 0, 0);
		mLocalPosition = CVector(0, 0, 0);
		mLocalScale = CVector(1, 1, 1);
		mLocalRotation = CVector(0, 0, 0);
		mParentPosition = CVector(0, 0, 0);
		mParentScale = CVector(0, 0, 0);
		mParentRotation = CVector(0, 0, 0);
		setPositon(mLocalPosition);
		setScale(mScale);
		setRotation(mRotation);
		mbDirty = true;
	}

	CMeshUnit::~CMeshUnit()
	{
		onUninitialise();
	}

	void CMeshUnit::onInitialise()
	{
		SafeRelease(mpMesh);
		SafeRelease(mpInstanceBuffer);
		CResourceBase* pResourceBase = CResourceManager::getSinglePtr()->findResource(mstrFileName);
		if (pResourceBase == nullptr)
		{
			mpMesh = dynamic_cast<CMesh*>(CResourceManager::getSinglePtr()->createResource(mstrFileName, Mesh));
		}
		else
		{
			mpMesh = dynamic_cast<CMesh*>(pResourceBase);
			mpMesh->AddRef();
		}
		mpMesh->initialise();
		mBoundBox = mpMesh->mBoundBox;
		exportPropertyToEditor();
	}


	void CMeshUnit::exportPropertyToEditor()
	{
		RegisterProperty("Mesh", mpMesh, _ADDRESS, Logic | GroundName, nullptr);
		RegisterProperty("Position", mLocalPosition, _FLOAT3, Editor, std::bind(&CMeshUnit::_setPosition, this));
		RegisterProperty("Scale", mLocalScale, _FLOAT3, Editor, std::bind(&CMeshUnit::_setScale, this));
		RegisterProperty("Rotation", mLocalRotation, _FLOAT3, Editor, std::bind(&CMeshUnit::_setRotation, this));
	}

	void CMeshUnit::onUninitialise()
	{
		SafeRelease(mpMesh);
		SafeRelease(mpMaterialUnit);
	}

	void CMeshUnit::updateUnitProperty(Property* pProperty)
	{
		for (auto item : mProperty)
		{
			if (&(*item) == pProperty)
			{
				mbDirty = true;
				pProperty->callback();
			}
		}
		if (mpMaterialUnit != nullptr)
		{
			mpMaterialUnit->updateUnitProperty(pProperty);
		}
	}

	void CMeshUnit::updateMaterial()
	{
		//updateMatricesToShader();
		if (nullptr != mpMaterialUnit)
		{
			mpMaterialUnit->updateMaterial();
		}
	}

	void CMeshUnit::setPositon(CVector& pt)
	{
		mParentPosition = pt;
		_setPosition();
	}

	void CMeshUnit::setRotation(CVector& rotation)
	{
		mParentRotation = rotation;
		_setRotation();
	}

	void CMeshUnit::setRotationX(float angle)
	{
		mParentRotation.x = angle;
		_setRotationX();
	}

	void CMeshUnit::setRotationY(float angle)
	{
		mParentRotation.y = angle;
		_setRotationY();
	}

	void CMeshUnit::setRotationZ(float angle)
	{
		mParentRotation.z = angle;
		_setRotationZ();
	}

	void CMeshUnit::setScale(CVector& scale)
	{
		mParentScale = scale;
		_setScale();
	}

	void CMeshUnit::setLocalPositon(CVector& pt)
	{
		mLocalPosition = pt;
		_setPosition();
	}

	void CMeshUnit::setLocalRotation(CVector& rotation)
	{
		mLocalRotation = rotation;
		_setRotation();
	}

	void CMeshUnit::setLocalRotationX(float angle)
	{
		mLocalRotation.x = angle;
		_setRotationX();
	}

	void CMeshUnit::setLocalRotationY(float angle)
	{
		mLocalRotation.y = angle;
		_setRotationY();
	}

	void CMeshUnit::setLocalRotationZ(float angle)
	{
		mLocalRotation.z = angle;
		_setRotationZ();
	}

	void CMeshUnit::setLocalScale(CVector& scale)
	{
		mLocalScale = scale;
		_setScale();
	}


	void CMeshUnit::update(float fDeltaTime)
	{
		if (mpMesh)
		{
			if (mbDirty)
			{
				D3DXMatrixMultiply(&mWorldMatrix, &mRotationMatrix[0], &mRotationMatrix[1]);
				D3DXMatrixMultiply(&mWorldMatrix, &mWorldMatrix, &mRotationMatrix[2]);
				D3DXMatrixMultiply(&mWorldMatrix, &mWorldMatrix, &mScaleMatrix);
				D3DXMatrixMultiply(&mWorldMatrix, &mWorldMatrix, &mPositionMatrix);
				mbDirty = false;
				mBoundBox.update(mWorldMatrix);
			}
			if (mUnitlVertices.size() > 0)
			{
			 	CSkeleton* pSkeleton = mpMesh->getSkeleton();
				if (nullptr != pSkeleton)
				{
					auto animation = pSkeleton->getAnimation();
					if (pSkeleton->GetKeyFrameCount() > 0)
					{
						memcpy(&mUnitlVertices[0], &mpMesh->mVerticesSkin[0], sizeof(VertexFormatVTNTBSkin) * mVerticesCount);
						pSkeleton->updateVertices(fDeltaTime, mUnitlVertices);
					}
				}
			}
		}
	}

	void CMeshUnit::buildMaterialUnit(CMaterialUnit* pUnit)
	{
		if (pUnit != nullptr && pUnit != mpMaterialUnit)
		{
			SafeRelease(mpMaterialUnit);
			mpMaterialUnit = pUnit;
			mpMaterialUnit->AddRef();
			mpMaterialUnit->exportPropertyToEditor();
			Property* pProperty = mpMaterialUnit->getPropertyFirst();
			while (pProperty != nullptr)
			{
				RegisterProperty(pProperty->strName, pProperty->pMemory, pProperty->dataType, pProperty->nFlag, pProperty->callback);
				pProperty = mpMaterialUnit->getPropertyNext();
			}
		}
	}

	void CMeshUnit::buildMaterialUnit(const std::string& strMaterial)
	{
		CMaterialUnit* pMaterialUnit = new CMaterialUnit;
		pMaterialUnit->setUnitFile(strMaterial);
		pMaterialUnit->onInitialise();
		bindMaterial(pMaterialUnit);
	}

	CMaterialUnit* CMeshUnit::getMaterialUnit()
	{
		return mpMaterialUnit;
	}

	CMesh* CMeshUnit::getBuildMesh() const
	{
		return mpMesh;
	}

	CBoundBox& CMeshUnit::getBoundBox()
	{
		return mBoundBox;
	}

	INTERSECTION& CMeshUnit::isPick(const CVector& v, bool isPickBound)
	{
		static INTERSECTION result;
		if (isPickBound)
		{
			return result;
		}
		else
		{
			CCamera* pCamera = dynamic_cast<CCamera*>(GEngine->getCurrentScene()->getCamera());
			CPoint3F vPickRayDir;
			CPoint3F vPickRayOrig;

			// Get the inverse view matrix
			const CMatrix& matView = pCamera->getViewMatrix();
			const CMatrix& matWorld = mWorldMatrix;
			CMatrix mWorldView = matWorld * matView;
			CMatrix m;
			D3DXMatrixInverse(&m, NULL, &mWorldView);

			vPickRayDir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
			vPickRayDir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
			vPickRayDir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
			vPickRayOrig.x = m._41;
			vPickRayOrig.y = m._42;
			vPickRayOrig.z = m._43;
			return isPick(CVector(&vPickRayOrig.x), CVector(&vPickRayDir.x), isPickBound);
		}
	}

	INTERSECTION& CMeshUnit::isPick(const CVector& origin, const CVector& dir, bool isPickBound)
	{
		static INTERSECTION result;
		float fBary1, fBary2, fDist;
		UINT32* pIndices = mpMesh->getIndices();
		INT32 faceNumber = mpMesh->getFaceNumber();
		INT32 index = 0;
		result.fDist = FLT_MAX;
		bool bcheck = false;
#ifdef WIN32
		VertexFormatVTNTB* pVertices = mpMesh->getVertices();
#else
		VertexFormatVTN* pVertices = mpMesh->getVertices();
#endif
		if (mpMesh->mVertices.size() > 0)
		{
			VertexFormatVTNTB* pVertices = mpMesh->getVertices();
			for (INT32 i = 0; i < faceNumber; ++i)
			{
				index = i * 3;
				if (GEngine->IntersectTriangle(&origin.x,
					&dir.x,
					&pVertices[pIndices[index + 0]].position.x,
					&pVertices[pIndices[index + 1]].position.x,
					&pVertices[pIndices[index + 2]].position.x,
					&fDist, &fBary1, &fBary2))
				{
					if (result.fDist > fDist)
					{
						result.fDist = fDist;
						result.fBary1 = fBary1;
						result.fBary2 = fBary2;
					}
				}
			}
		}
		else
		{
			VertexFormatVTNTBSkin* pVertices = mpMesh->getVerticesSkin();
			if (nullptr != pVertices)
			{
				for (INT32 i = 0; i < faceNumber; ++i)
				{
					index = i * 3;
					if (GEngine->IntersectTriangle(&origin.x,
						&dir.x,
						&pVertices[pIndices[index + 0]].position.x,
						&pVertices[pIndices[index + 1]].position.x,
						&pVertices[pIndices[index + 2]].position.x,
						&fDist, &fBary1, &fBary2))
					{
						if (result.fDist > fDist)
						{
							result.fDist = fDist;
							result.fBary1 = fBary1;
							result.fBary2 = fBary2;
						}
					}
				}
			}
		}
		return result;
	}

	void CMeshUnit::render(DeviceContext* pDeviceContext)
	{
		if (mpMaterialUnit != nullptr)
		{
			if (mpMesh->getSkeleton() != nullptr)
			{
				D3D11_MAPPED_SUBRESOURCE mappedResource;
				// Lock the vertex buffer so it can be written to.
				HRESULT result = pDeviceContext->Map(mpMesh->mpVertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
				if (FAILED(result))
				{
					return;
				}

				// Copy the data into the vertex buffer.
				memcpy(mappedResource.pData, &mUnitlVertices[0], sizeof(VertexFormatVTNTBSkin) * mVerticesCount);
				// Unlock the vertex buffer.
				pDeviceContext->Unmap(mpMesh->mpVertexBuffer, 0);
			}

			// Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
			//pDeviceContext->IASetPrimitiveTopology((D3D_PRIMITIVE_TOPOLOGY)mTopology);
			mpMaterialUnit->apply(pDeviceContext);

			if (0 == mInstanceCount)
			{
				// Set the vertex buffer to active in the input assembler so it can be rendered.
				pDeviceContext->IASetVertexBuffers(0, 1, &mBufferPointers[0], &mStrides[0], &mOffsets[0]);

				// Set the index buffer to active in the input assembler so it can be rendered.
				pDeviceContext->IASetIndexBuffer(mpMesh->mpIndexBuffer, (DXGI_FORMAT)mpMesh->mIndeiceType, 0);

				pDeviceContext->DrawIndexed(mpMesh->mIndexCount, 0, 0);
			}
			else
			{
				// Set the vertex buffer to active in the input assembler so it can be rendered.
				pDeviceContext->IASetVertexBuffers(0, 2, mBufferPointers, mStrides, mOffsets);
				pDeviceContext->DrawInstanced(mpMesh->mVertexCount, mInstanceCount, 0, 0);
			}
		}
	}

	void CMeshUnit::renderPoint(DeviceContext* pDeviceContext)
	{

	}

	void CMeshUnit::renderTriangleList(DeviceContext* pDeviceContext)
	{

	}

	void CMeshUnit::updateMatrices()
	{

	}

	void CMeshUnit::updateMatricesToShader()
	{
		CRendererEngine::getSinglePtr()->setWorldMatrix(&mWorldMatrix);
		auto& matrices = CRendererEngine::getSinglePtr()->getTransposeMatrices();
		mpMaterialUnit->getShaderUnit(0)->updateVSConstBuffer(0, &matrices[0]);
	}

	void CMeshUnit::_setPosition()
	{
		mbDirty = true;
		mPosition = mParentPosition + mLocalPosition;
		mPositionMatrix.m[3][0] = mPosition.x;
		mPositionMatrix.m[3][1] = mPosition.y;
		mPositionMatrix.m[3][2] = mPosition.z;
	//	mBoundBox.setPosition(CPoint3F(&mPosition.x));
	}

	void CMeshUnit::_setRotation()
	{
		mbDirty = true;
		mRotation = mParentRotation + mLocalRotation;
		_setRotationX();
		_setRotationY();
		_setRotationZ();
	}

	void CMeshUnit::_setScale()
	{
		mbDirty = true;
		mScale = mLocalScale + mParentScale;
		mScale.x = mLocalScale.x * mParentScale.x;
		mScale.y = mLocalScale.y * mParentScale.y;
		mScale.z = mLocalScale.z * mParentScale.z;
		mScaleMatrix.m[0][0] = mScale.x;
		mScaleMatrix.m[1][1] = mScale.y;
		mScaleMatrix.m[2][2] = mScale.z;
	//	mBoundBox.setScale(CPoint3F(&mScale.x));
	}


	void CMeshUnit::_setRotationX()
	{
		mbDirty = true;
		mRotation.x = mParentRotation.x + mLocalRotation.x;
		D3DXMatrixRotationX(&mRotationMatrix[0], mRotation.x);
	}

	void CMeshUnit::_setRotationY()
	{
		mbDirty = true;
		mRotation.y = mParentRotation.y + mLocalRotation.y;
		D3DXMatrixRotationY(&mRotationMatrix[1], mRotation.y);
	}

	void CMeshUnit::_setRotationZ()
	{
		mbDirty = true;
		mRotation.z = mParentRotation.z + mLocalRotation.z;
		D3DXMatrixRotationZ(&mRotationMatrix[2], mRotation.z);
	}

	void CMeshUnit::bindMesh(CMesh* pMesh)
	{
		if (mpMesh != pMesh)
		{
			SafeRelease(mpMesh);
			mpMesh = pMesh;
			mpMesh->AddRef();
			mStrides[0] = mpMesh->mVertexTypeSize;
			mOffsets[0] = 0;
			mBufferPointers[0] = mpMesh->mpVertexBuffer;
			if (pMesh->mVerticesSkin.size() > 0)
			{
				mBoundBox.calculation(&pMesh->mVerticesSkin[0], pMesh->mVertexCount);
			}
			else if( pMesh->mVertices.size() > 0)
			{
				mBoundBox.calculation(&pMesh->mVertices[0], pMesh->mVertexCount);
			}
			else if (pMesh->mVerticesPT.size() > 0)
			{
				mBoundBox.calculation(&pMesh->mVerticesPT[0], pMesh->mVertexCount);
			}
			else if (pMesh->mVerticesPC.size() > 0)
			{
				mBoundBox.calculation(&pMesh->mVerticesPC[0], pMesh->mVertexCount);
			}
			mBoundBox.relateMeshUnit(this);
			size_t verticesCount = mpMesh->mVerticesSkin.size();
			if (mpMesh->mVerticesSkin.size() > 0)
			{
				mUnitlVertices.resize(verticesCount);
				mVerticesCount = verticesCount;
				memcpy(&mUnitlVertices[0], &mpMesh->mVerticesSkin[0], sizeof(VertexFormatVTNTBSkin) * mVerticesCount);
			}
		}
	}

	void CMeshUnit::bindMaterial(CMaterialUnit* pMaterialUnit)
	{
		if (pMaterialUnit != mpMaterialUnit)
		{
			SafeRelease(mpMaterialUnit);
			mpMaterialUnit = pMaterialUnit;
			mpMaterialUnit->AddRef();
		}
	}

	void CMeshUnit::bindMaterial(CMaterial* pMaterialUnit)
	{
		SafeRelease(mpMaterialUnit);
		mpMaterialUnit = new CMaterialUnit;
	}

	void CMeshUnit::bindMaterial(const std::string& szMaterial)
	{
		SafeRelease(mpMaterialUnit);
		mpMaterialUnit = new CMaterialUnit;
		mpMaterialUnit->setUnitFile(szMaterial);
		mpMaterialUnit->onInitialise();
		bindMaterial(mpMaterialUnit);
	}

	CMatrix& CMeshUnit::getMatrix()
	{
		return mWorldMatrix;
	}

	void CMeshUnit::setInstance(CGPUBuffer* pBuf, int nTypeSize, int nCount)
	{
		SafeRelease(mpInstanceBuffer);
		mpInstanceBuffer = pBuf;
		mpInstanceBuffer->AddRef();
		mInstanceTypeSize = nTypeSize;
		mInstanceCount = nCount;
		mStrides[1] = nTypeSize;
		mBufferPointers[1] = mpInstanceBuffer;
	}
	

	//////////////////////////////////////////////////////////////////////////
	CSkinMeshUnit::CSkinMeshUnit()
	{

	}

	CSkinMeshUnit::~CSkinMeshUnit()
	{

	}


	void CSkinMeshUnit::render(DeviceContext* pDeviceContext)
	{
	}

	void CSkinMeshUnit::renderPoint(DeviceContext* pDeviceContext)
	{	
		GEngine->getDevice()->turnZBufferOff(pDeviceContext);
		GEngine->getDevice()->turnOnNoCulling(pDeviceContext);
		GEngine->getDevice()->turnOffAlphaBlending(pDeviceContext);
		
		// Turn on stream out
		ID3D11Buffer* pBuffers[1] = { mGpuBuffer};
	
		UINT32 offset[1] = { 0 };

		pDeviceContext->SOSetTargets(1, pBuffers, offset);

		// Set the vertex buffer to active in the input assembler so it can be rendered.
		pDeviceContext->IASetVertexBuffers(0, 1, mBufferPointers, mStrides, offset);

		pDeviceContext->Draw(mpMesh->mVertexCount, 0);

	}

	void CSkinMeshUnit::renderTriangleList(DeviceContext* pDeviceContext)
	{
		mpMaterialUnit->apply(pDeviceContext);
		ID3D11Buffer* pBuffers[1] = { mGpuBuffer };

		UINT32 stride[1] = { sizeof(STREAM_OUT_VERTEX) };
		UINT32 offset[1] = { 0 };
		if (0 == mInstanceCount)
		{
			// Set the vertex buffer to active in the input assembler so it can be rendered.
			pDeviceContext->IASetVertexBuffers(0, 1, pBuffers, stride, offset);

			// Set the index buffer to active in the input assembler so it can be rendered.
			pDeviceContext->IASetIndexBuffer(mpMesh->mpIndexBuffer, (DXGI_FORMAT)mpMesh->mIndeiceType, 0);

			pDeviceContext->DrawIndexed(mpMesh->mIndexCount, 0, 0);
		}
		else
		{
			// Set the vertex buffer to active in the input assembler so it can be rendered.
			pDeviceContext->IASetVertexBuffers(0, 2, mBufferPointers, mStrides, mOffsets);
			pDeviceContext->DrawInstanced(mpMesh->mVertexCount, mInstanceCount, 0, 0);
		}
	}

	void CSkinMeshUnit::updateMatrices()
	{
		D3DMATRIX mm[255];
		memcpy(mm, &mFrameMatrices[0]->m[0][0], sizeof(mm));
		mpMaterialUnit->updateVSConstBuffer(1, &mm[0], 0);
		mpMaterialUnit->updateTextureConstBuffer(0, &mm[0], 0);
		mpMaterialUnit->updateTextureBuffer(0, &mm[0], 0);
		mpMaterialUnit->updateTypeBuffer(0, &mm[0], 0);
	}

	bool CSkinMeshUnit::createSteamOutBuffer()
	{
		mGpuBuffer = GEngine->getDevice()->createSteamOutBuffer<STREAM_OUT_VERTEX>((int)mpMesh->getVerticeCount());
		return mGpuBuffer != nullptr ? true : false;
	}

	int CSkinMeshUnit::getSkeletonIndex()
	{
		return mSkeletonIndex;
	}

	void CSkinMeshUnit::setSkeletonIndex(int nIndex)
	{
		mSkeletonIndex = nIndex;
	}

	void CSkinMeshUnit::pushFrameMatrix(CMatrix* pMatrix)
	{
		mFrameMatrices.push_back(pMatrix);
	}

	//////////////////////////////////////////////////////////////////////////
	CMaterialUnit::CMaterialUnit()
	: mpMaterial(nullptr)
	{
		mstrFileName = "";
	//	mUnitFlag = (UnitEnum::render | UnitEnum::client | UnitEnum::material);
	}

	CMaterialUnit::~CMaterialUnit()
	{
		onUninitialise();
	}

	void CMaterialUnit::onInitialise()
	{
		SafeRelease(mpMaterial);
		CResourceBase* pResourceBase = CResourceManager::getSinglePtr()->findResource(mstrFileName);
		if (pResourceBase == nullptr)
		{
			mpMaterial = dynamic_cast<CMaterial*>(CResourceManager::getSinglePtr()->createResource(mstrFileName, Material));
		}
		else
		{
			pResourceBase->AddRef();
			mpMaterial = dynamic_cast<CMaterial*>(pResourceBase);
		}
		memcpy(&mConstBuffer, &mpMaterial->mConstBuffer, sizeof(_constBuffer));
		mFillCullMode = mpMaterial->mFillCullMode;
		mDepthStatus = mpMaterial->mDepthStatus;
		mTransparent = mpMaterial->mTransparent;
		mTopology = mpMaterial->mTopology;
		
		for (auto item : mpMaterial->mpShaders)
		{
			auto pUnit = new CShaderUnit(item);
			mpShaderUnits.push_back(pUnit);
		}
		exportPropertyToEditor();
	}

	void CMaterialUnit::exportPropertyToEditor()
	{
		RegisterProperty("Material", mpMaterial, _ADDRESS, Logic | GroundName, nullptr);
		RegisterProperty("DiffuseColor", &mConstBuffer.mDiffuseColor[0], _COLOR32, Editor, std::bind(&CMaterialUnit::setDiffuseColor, this));
		RegisterProperty("AmbientColor", &mConstBuffer.mAmbientColor[0], _COLOR32, Editor, std::bind(&CMaterialUnit::setAmbientColor, this));
		RegisterProperty("SpecularColor", &mConstBuffer.mSpecularColor[0], _COLOR32, Editor, std::bind(&CMaterialUnit::setSpecularColor, this));
		RegisterProperty("SpecularPower", &mConstBuffer.mSpecularPower, _FLOAT, Editor, std::bind(&CMaterialUnit::setSpecularPower, this));
		//RegisterProperty("Textures", &mpMaterial->mTextures, _TEXTURE, Editor);
	}

	void CMaterialUnit::updateSpace()
	{

	}

	void CMaterialUnit::updateMaterial()
	{
		for (auto& item : mLights)
		{
			for (auto _item : mpShaderUnits)
			{
				_item->updatePSConstBuffer(item->getName(), item->getLightData());
			}
		}
	}

	void CMaterialUnit::setDiffuseColor()
	{
		for (auto item : mpShaderUnits)
		{
			item->updatePSConstBuffer("DiffuseColor", mConstBuffer.mDiffuseColor);
		}
	}

	void CMaterialUnit::setAmbientColor()
	{
		for (auto item : mpShaderUnits)
		{
			item->updatePSConstBuffer("AmbientColor", mConstBuffer.mAmbientColor);
		}
	}

	void CMaterialUnit::setSpecularColor()
	{
		for (auto item : mpShaderUnits)
		{
			item->updatePSConstBuffer("SpecularColor", mConstBuffer.mSpecularColor);
		}
	}

	void CMaterialUnit::setSpecularPower()
	{
		for (auto item : mpShaderUnits)
		{
			item->updatePSConstBuffer("SpecularPower", &mConstBuffer.mSpecularPower);
		}
	}

	void CMaterialUnit::addLight(CLightActor* pLight)
	{
		auto item = std::find(mLights.begin(), mLights.end(), pLight);
		if (item == mLights.end())
		{
			mLights.push_back(pLight);
			for (auto item : mpShaderUnits)
			{
				item->addPSParam(pLight->getName(), pLight->getLigteDataLength(),
					pLight->getRegister(), pLight->getPackoffset());
			}
		}
	}

	void CMaterialUnit::removeLight(CLightActor* pLight)
	{
		auto item = std::find(mLights.begin(), mLights.end(), pLight);
		if (item != mLights.end())
		{
			mLights.erase(item);
		}
	}
	
	INT CMaterialUnit::getTopology()
	{
		return mTopology;
	}

	INT CMaterialUnit::getFillCllMode()
	{
		return mFillCullMode;
	}

	bool CMaterialUnit::isShadow()
	{
		return mpMaterial->mShadow != 0 ? true : false;
	}

	INT32 CMaterialUnit::getShaderUnitSize()
	{
		return (INT32)mpShaderUnits.size();
	}

	ID3D11SamplerState* CMaterialUnit::getSampler(int nIndex) const
	{
		if(nullptr != mpMaterial)
		{
			return mpMaterial->getSample(nIndex);
		}
		return nullptr;
	}

	void CMaterialUnit::setViewMatrixForAllShaderUnit(CMatrix* pMatrix)
	{
		for (auto item : mpShaderUnits)
		{
			item->setViewMatrix(pMatrix);
		}
	}

	void CMaterialUnit::setProjectMatrixForAllShaderUnit(CMatrix* pMatrix)
	{
		for (auto item : mpShaderUnits)
		{
			item->setProjectMatrix(pMatrix);
		}
	}

	void CMaterialUnit::update(float fDeltaTime)
	{
		if (mbDirty && mpMaterial)
		{

		}
	}

	void CMaterialUnit::updateUnitProperty(Property* pProperty)
	{

	}


	void CMaterialUnit::onUninitialise()
	{
		SafeRelease(mpMaterial);
		for (auto item : mpShaderUnits)
		{
			SafeDelete(item);
		}
	}

	INT32 CMaterialUnit::getShaderId(int index )
	{
		if (index < mpShaderUnits.size())
		{
			return mpShaderUnits[index]->getShader()->getResourceID();
		}
		else
		{
			return -1;
		}
	}

	CShaderUnit* CMaterialUnit::getShaderUnit(int index)
	{
		if (index < mpShaderUnits.size())
		{
			return mpShaderUnits[index];
		}
		return nullptr;
	}

	void CMaterialUnit::apply(DeviceContext* pDeviceContext)
	{
		if (mpMaterial != nullptr)
		{
			//if (mDepthStatus != GEngine->getDevice()->getCurrentDepthStatus())
			{
				if (0 == mDepthStatus)
				{
					GEngine->getDevice()->turnZBufferOff(pDeviceContext);
				}
				else
				{
					GEngine->getDevice()->turnZBufferOn(pDeviceContext);
				}
			}
			//if (mCullMode != GEngine->getDevice()->getCurrentCullMode())
			{
				switch (mFillCullMode)
				{
				case 1:				//D3D11_CULL_NONE
					GEngine->getDevice()->turnOnNoCulling(pDeviceContext);
					break;
				case 2:				//D3D11_CULL_FRONT
					GEngine->getDevice()->turnOnFrontCulling(pDeviceContext);
					break;
				case 3:				//D3D11_CULL_BACK
					GEngine->getDevice()->turnOnBackCulling(pDeviceContext);
					break;
				case 4:				//D3D11_CULL_SOLID_NONE
					GEngine->getDevice()->turnOnNoCullingSolid(pDeviceContext);
					break;
				case 5:				//D3D11_CULL_SOLID_FRONT
					GEngine->getDevice()->turnOnFrontCullingSolid(pDeviceContext);
					break;
				case 6:				//D3D11_SOLID_CULL_BACK
					GEngine->getDevice()->turnOnBackCullingSolid(pDeviceContext);
					break;
				default:
					GEngine->getDevice()->turnOnFrontCulling(pDeviceContext);
				}
			}
			//if (mTransparent != GEngine->getDevice()->getCurrentTransparent())
			{
				if( 0 == mTransparent )
				{
					GEngine->getDevice()->turnOffAlphaBlending(pDeviceContext);
				}
				else
				{
					GEngine->getDevice()->turnOnAlphaBlending(pDeviceContext);
				}
			}
			for( auto& item : mLights )
			{
				for (auto _item : mpShaderUnits)
				{
					_item->updatePSConstBuffer(item->getLightName().c_str(), item->getLightData());
				}
			}
			mpMaterial->apply(pDeviceContext);
		}
	}

	void CMaterialUnit::unApply(DeviceContext* pDeviceContext)
	{

	}

	bool CMaterialUnit::addPSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addPSParam(name, size, nRegister, offset);
		}
		return true;
	}

	bool CMaterialUnit::addDSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addDSParam(name, size, nRegister, offset);
		}
		return true;
	}

	bool CMaterialUnit::addHSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addHSParam(name, size, nRegister, offset);
		}
		return true;
	}
	bool CMaterialUnit::addVSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addVSParam(nullptr, size, nRegister, offset);
		}
		return true;
	}

	bool CMaterialUnit::addTextureBufferParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addTextureConstBufferParam(nullptr, size, nRegister, offset);
		}
		return true;
	}

	bool CMaterialUnit::addGSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addGSParam(nullptr, size, nRegister, offset);
		}
		return true;
	}
	
	bool CMaterialUnit::addStructedBuffer(const std::string& name, INT32 structSize, INT32 size, INT32 nRegister, int offset)
	{
		for (auto item : mpShaderUnits)
		{
			item->addStructedBuffer(nullptr, structSize, size, nRegister, offset);
		}
		return true;
	}

	void CMaterialUnit::updateVSConstBuffer(UINT32 uStartSlot, void* pData, int nShaderIndex)
	{
		if (nullptr != mpMaterial)
		{
			if (nShaderIndex < mpShaderUnits.size())
			{
				auto pShader = mpShaderUnits[nShaderIndex];
				if (nullptr != pShader)
				{
					pShader->updateVSConstBuffer(uStartSlot, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateTextureConstBuffer(UINT32 uStartSlot, void* pData, int nShaderIndex /*= 0*/)
	{
		if (nullptr != mpMaterial)
		{
			if (nShaderIndex < mpShaderUnits.size())
			{
				auto pShader = mpShaderUnits[nShaderIndex];
				if (nullptr != pShader)
				{
					pShader->updateTextureConstBuffer(uStartSlot, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateTextureBuffer(UINT32 uStartSlot, void* pData, int nShaderIndex /*= 0*/)
	{
		if (nullptr != mpMaterial)
		{
			if (nShaderIndex < mpShaderUnits.size())
			{
				auto pShader = mpShaderUnits[nShaderIndex];
				if (nullptr != pShader)
				{
					pShader->updateTextureBuffer(uStartSlot, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateTypeBuffer(UINT32 uStartSlot, void* pData, int nShaderIndex /*= 0*/)
	{
		if (nullptr != mpMaterial)
		{
			if (nShaderIndex < mpShaderUnits.size())
			{
				auto pShader = mpShaderUnits[nShaderIndex];
				if (nullptr != pShader)
				{
					pShader->updateTypeBuffer(uStartSlot, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateStructedBuffer(UINT32 uStartSlot, void* pData, int nShaderIndex /*= 0*/)
	{
		if (nullptr != mpMaterial)
		{
			if (nShaderIndex < mpShaderUnits.size())
			{
				auto pShader = mpShaderUnits[nShaderIndex];
				if (nullptr != pShader)
				{
					pShader->updateStructedBuffer(uStartSlot, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateHSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpMaterial)
		{
			for (auto item : mpShaderUnits)
			{
				if (nullptr != item->getShader())
				{
					item->updateHSConstBuffer(name, pData);
				}
			}
		}
	}


	void CMaterialUnit::updateDSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpMaterial)
		{
			for (auto item : mpShaderUnits)
			{
				if (nullptr != item->getShader())
				{
					item->updateDSConstBuffer(name, pData);
				}
			}
		}
	}

	void CMaterialUnit::updatePSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpMaterial)
		{
			for (auto item : mpShaderUnits)
			{
				if (nullptr != item->getShader())
				{
					item->updatePSConstBuffer(name, pData);
				}
			}
		}
	}

	void CMaterialUnit::updateGSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpMaterial)
		{
			for (auto item : mpShaderUnits)
			{
				if (nullptr != item->getShader())
				{
					item->updateGSConstBuffer(name, pData);
				}
			}
		}
	}

	bool CMaterialUnit::isZbufferWrite()
	{
		return mpMaterial->mDepthStatus != 0 ? true : false;
	}

	bool CMaterialUnit::isAlpha()
	{
		return mpMaterial->mTransparent != 0 ? true : false;
	}

	void CMaterialUnit::setTexture(CTexture* pTexture, int index)
	{
		auto item = mpMaterial->mTextures.begin();
		auto iEnd = mpMaterial->mTextures.end();
		int iMove = 0;
		while (item != iEnd)
		{
			if (iMove++ == index && pTexture != mpMaterial->mTextures[index])
			{
				SafeRelease(mpMaterial->mTextures[index]);
				mpMaterial->mTextures[index] = pTexture;
				pTexture->AddRef();
				break;
			}
		}
	}

	void CMaterialUnit::insertTexture(CTexture* pTexture, int index)
	{	
		if (pTexture->isSamplerStateEmpty())
		{
			pTexture->setSampleState(mpMaterial->getSample(0));
		}
		if (mpMaterial->mTextures.size() < index+1)
		{
			std::vector<CTexture*> textures(mpMaterial->mTextures);
			int nSize = mpMaterial->mTextures.size() + 1;
			mpMaterial->mTextures.resize(nSize);
			int i = 0;
			for (auto item : textures)
			{
				mpMaterial->mTextures[i++] = item;
			}
		}
		mpMaterial->mTextures[index] = pTexture;
	}

	//////////////////////////////////////////////////////////////////////////
	CFontUnit::CFontUnit(CFont* pFont)
	{
		mpFont = pFont;
		mpFont->AddRef();
	}

	CFontUnit::~CFontUnit()
	{
		SafeRelease(mpFont);
	}

	const CTexture* const CFontUnit::getFontTexture() const
	{
		return nullptr != mpFont ? mpFont->getFontTexture() : nullptr;
	}

	void CFontUnit::setFontShowMode(UINT mode)
	{
		mFontShowMode = mode;
	}


	void CFontUnit::setFontSize(CPoint2F size)
	{
		mFontSize = size;
	}

	void CFontUnit::setFontColor(CPoint4F color)
	{
		mFontColor = color;
	}
	void CFontUnit::setDrawText(const std::string& text, float x, float y, float width, float height)
	{
		mbUpdate = true;
		mString = text;
		mX = x;
		mY = y;
		mWidth = width;
		mHeight = height;
	}

	UINT CFontUnit::getFontShowMode()
	{
		return mFontShowMode;
	}

	CPoint2F CFontUnit::getFontSize()
	{
		return mFontSize;
	}

	CPoint4F CFontUnit::getFontColor()
	{
		return mFontColor;
	}
	
	const std::vector<VertexFormatVTC>& CFontUnit::getTextBuffer()  
	{
		_update();
		return mFontContentBuffer;
	}

	void CFontUnit::_update()
	{
		if (mbUpdate)
		{
			mbUpdate = false;
			INT32 l = mString.length();
			if (l > 0)
			{
				auto& config = GEngine->getDevice()->getConfig();
				float frameHalfWidth = (float)config.screenWidth / 2;
				float frameHalfHeight = (float)config.screenHeight / 2;
				auto&& pt = calculatePositionByShowMode(mString, mX, mY, mWidth, mHeight);
				float x = pt.x - frameHalfWidth;
				float y = frameHalfHeight - pt.y;
				int index = 0;
				int textCount = 0;
				mFontContentBuffer.resize(l * 6);
				const char* pCharBuffer = mString.c_str();
				INT32 letter = 0;

				for (UINT32 i = 0; i < mString.size(); ++i)
				{
					letter = ((INT32)pCharBuffer[i]) - 32;

					// If the letter is a space then just move over three pixels.
					if (letter != 0)
					{
						index = i * 6;
						++textCount;
						// First triangle in quad.
						mFontContentBuffer[index + 0].position = CPoint3F(x, y, 0.0f);  // Top left.
						mFontContentBuffer[index + 0].uv = CPoint2F(mpFont->mFontCells[letter].left, 0.0f);
						mFontContentBuffer[index + 0].color = mFontColor;

						mFontContentBuffer[index + 1].position = CPoint3F((x + mpFont->mFontCells[letter].size), (y - mFontSize.y), 0.0f);  // Bottom right.
						mFontContentBuffer[index + 1].uv = CPoint2F(mpFont->mFontCells[letter].right, 1.0f);
						mFontContentBuffer[index + 1].color = mFontColor;

						mFontContentBuffer[index + 2].position = CPoint3F(x, (y - mFontSize.y), 0.0f);  // Bottom left.
						mFontContentBuffer[index + 2].uv = CPoint2F(mpFont->mFontCells[letter].left, 1.0f);
						mFontContentBuffer[index + 2].color = mFontColor;

						// Second triangle in quad.
						mFontContentBuffer[index + 3].position = CPoint3F(x, y, 0.0f);  // Top left.
						mFontContentBuffer[index + 3].uv = CPoint2F(mpFont->mFontCells[letter].left, 0.0f);
						mFontContentBuffer[index + 3].color = mFontColor;

						mFontContentBuffer[index + 4].position = CPoint3F(x + mpFont->mFontCells[letter].size, y, 0.0f);  // Top right.
						mFontContentBuffer[index + 4].uv = CPoint2F(mpFont->mFontCells[letter].right, 0.0f);
						mFontContentBuffer[index + 4].color = mFontColor;

						mFontContentBuffer[index + 5].position = CPoint3F((x + mpFont->mFontCells[letter].size), (y - mFontSize.y), 0.0f);  // Bottom right.
						mFontContentBuffer[index + 5].uv = CPoint2F(mpFont->mFontCells[letter].right, 1.0f);
						mFontContentBuffer[index + 5].color = mFontColor;
						// Update the x location for drawing by the size of the letter and one pixel.
						x += mpFont->mFontCells[letter].size + 2.0f;
					}
					else
					{
						x += 3.0f;
					}
				}
				mFontContentBuffer.resize(textCount * 6);
				mFontContentBuffer.shrink_to_fit();
			}
		}
	}

	CPoint2F CFontUnit::calculatePositionByShowMode( const std::string& text, float x, float y, float width, float height)
	{
		CPoint2F pt = { x,y };
		INT32 letter = 0;
		const char* pChBuffer = text.c_str();
		float pt_x = 0;
		for (UINT32 i = 0; i < text.size(); ++i)
		{
			letter = ((INT32)pChBuffer[i]) - 32;

			// If the letter is a space then just move over three pixels.
			if (letter != 0)
			{
				pt_x += mpFont->mFontCells[letter].size + 1.0f;
			}
			else
			{
				pt_x += 3.0f;
			}
		}	

		if (mFontShowMode & ShowMode::Center)
		{
			pt.x = int(x + (width - pt_x ) / 2);
			pt.y = int(y + (height - mFontSize.y )/2);
		}
		else
		{
			if (mFontShowMode & ShowMode::Left)
			{
				pt.x = x;
			}
			if (mFontShowMode & ShowMode::Top)
			{
				pt.y = y;
			}
			if (mFontShowMode & ShowMode::Right)
			{
				pt.x = x + width - pt_x;
			}
			if (mFontShowMode & ShowMode::Bottom)
			{
				pt.y = y + height - mFontSize.y;
			}
			if (mFontShowMode & ShowMode::H_Center)
			{
				pt.x = int(x + ( width - pt_x ) / 2);
			}
			if (mFontShowMode & ShowMode::U_Center)
			{
				pt.y = int(y + ( height - mFontSize.y ) / 2);
			}
		}
		return pt;
	}

	CFont* CFontUnit::getFont()
	{
		return mpFont;
	}

	CPoint2F CFontUnit::getCharacterSize(char nChar)
	{
		CPoint2F size(0, 0);
		if (nullptr != mpFont)
		{
			int index = nChar - 32;
			if (index >= 0 && index < 94)
			{
				size.x = mpFont->mFontCells[index].size;
				size.y = mFontSize.y;
			}
		}
		return size;
	}


	//////////////////////////////////////////////////////////////////////////
	CShaderUnit::CShaderUnit(CShader* pShader)
	: mpShader(pShader)
	{
		mTopology = pShader->mTopology;
		for( auto item : mpShader->mVertexConstBufferMap )
		{
			addVSParam("", std::get<0>(item.second), item.first, std::get<3>(item.second));
		}

		for( auto item : mpShader->mHullParamMap)
		{
			addHSParam(item.first, std::get<1>(item.second), std::get<0>(item.second), std::get<4>(item.second));
		}

		for (auto item : mpShader->mDomainParamMap)
		{
			addDSParam(item.first, std::get<1>(item.second), std::get<0>(item.second), std::get<4>(item.second));
		}

		for (auto item : mpShader->mGeometryParamMap)
		{
			addGSParam(item.first, std::get<1>(item.second), std::get<0>(item.second), std::get<4>(item.second));
		}

		for (auto item : mpShader->mPixelParamMap)
		{
			addPSParam(item.first, std::get<1>(item.second), std::get<0>(item.second), std::get<4>(item.second));
		}
	}

	CShaderUnit::~CShaderUnit()
	{
		SafeRelease(mpShader);
		for (auto item : mVSDataMaps)
		{
			auto& tuple = item.second;
			SafeDelete( std::get<1>(tuple));
		}
		for (auto item : mHSDataMaps)
		{
			auto& tuple = item.second;
			SafeDelete(std::get<1>(tuple));
		}
		for (auto item : mDSDataMaps)
		{
			auto& tuple = item.second;
			SafeDelete(std::get<1>(tuple));
		}
		for (auto item : mPSDataMaps)
		{
			auto& tuple = item.second;
			SafeDelete( std::get<1>(tuple));
		}
		for (auto item : mGSDataMaps)
		{
			auto& tuple = item.second;
			SafeDelete(std::get<1>(tuple));
		}
	}
	void CShaderUnit::apply(DeviceContext* pDeviceContext)
	{
		if (nullptr != mpShader)
		{
			applyConstBuffer();
			mpShader->commitToGpu(pDeviceContext);
		}
	}

	bool CShaderUnit::updateVSConstBuffer(int nRegistIndex, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mVSDataMaps.find(nRegistIndex);
			if (item != mVSDataMaps.end())
			{
				auto& pair = (item->second);
				memcpy(std::get<1>(pair),pData, std::get<0>(pair));
			}
			else 
			{
				auto item = mpShader->mVertexConstBufferMap.find(nRegistIndex);
				if (item != mpShader->mVertexConstBufferMap.end())
				{
					auto& pair = item->second;
					int size = std::get<0>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mVSDataMaps[nRegistIndex] = std::tuple<int, void*, int>(size, pNewData, std::get<3>(pair) );
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updateTextureConstBuffer(int nRegistIndex, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mTextureConstBufferMaps.find(nRegistIndex);
			if (item != mTextureConstBufferMaps.end())
			{
				auto& pair = (item->second);
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else
			{
				auto item = mpShader->mTextureConstBufferMap.find(nRegistIndex);
				if (item != mpShader->mTextureConstBufferMap.end())
				{
					auto& pair = item->second;
					int size = std::get<0>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mTextureConstBufferMaps[nRegistIndex] = std::tuple<int, void*, int>(size, pNewData, std::get<3>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updateTextureBuffer(int nRegistIndex, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mTextureBufferMaps.find(nRegistIndex);
			if (item != mTextureBufferMaps.end())
			{
				auto& pair = (item->second);
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else
			{
				auto item = mpShader->mTextureBufferMap.find(nRegistIndex);
				if (item != mpShader->mTextureBufferMap.end())
				{
					auto& pair = item->second;
					int size = std::get<0>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mTextureBufferMaps[nRegistIndex] = std::tuple<int, void*, int>(size, pNewData, std::get<3>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updateTypeBuffer(int nRegistIndex, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mTypeBufferMaps.find(nRegistIndex);
			if (item != mTypeBufferMaps.end())
			{
				auto& pair = (item->second);
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else
			{
				auto item = mpShader->mTypeBufferMap.find(nRegistIndex);
				if (item != mpShader->mTypeBufferMap.end())
				{
					auto& pair = item->second;
					int size = std::get<0>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mTypeBufferMaps[nRegistIndex] = std::tuple<int, void*, int>(size, pNewData, std::get<3>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updateStructedBuffer(int nRegistIndex, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mStructBufferMaps.find(nRegistIndex);
			if (item != mStructBufferMaps.end())
			{
				auto& pair = (item->second);
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else
			{
				auto item = mpShader->mStructBufferMap.find(nRegistIndex);
				if (item != mpShader->mStructBufferMap.end())
				{
					auto& pair = item->second;
					int size = std::get<0>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mStructBufferMaps[nRegistIndex] = std::tuple<int, void*, int>(size, pNewData, std::get<3>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updateHSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mHSDataMaps.find(name);
			if (item != mHSDataMaps.end())
			{
				auto& pair = item->second;
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else if (mpShader->mHullParamMap.find(name) != mpShader->mHullParamMap.end())
			{
				auto item = mpShader->mHullParamMap.find(name);
				if (item != mpShader->mHullParamMap.end())
				{
					auto& pair = item->second;
					int size = std::get<1>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mHSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, std::get<4>(pair));
				}
			}
		}
		return false;
	}


	bool CShaderUnit::updateDSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mDSDataMaps.find(name);
			if (item != mDSDataMaps.end())
			{
				auto& pair = item->second;
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else if (mpShader->mDomainParamMap.find(name) != mpShader->mDomainParamMap.end())
			{
				auto item = mpShader->mDomainParamMap.find(name);
				if (item != mpShader->mDomainParamMap.end())
				{
					auto& pair = item->second;
					int size = std::get<1>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mDSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, std::get<4>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::updatePSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mPSDataMaps.find(name);
			if (item != mPSDataMaps.end())
			{
				auto& pair = item->second;
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else if( mpShader->mPixelParamMap.find(name) != mpShader->mPixelParamMap.end())
			{
				auto item = mpShader->mPixelParamMap.find(name);
				if (item != mpShader->mPixelParamMap.end())
				{
					auto& pair = item->second;
					int size = std::get<1>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mPSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, std::get<4>(pair));
				}
			}
		}		
		return false;
	}

	bool CShaderUnit::updateGSConstBuffer(const std::string& name, void* pData)
	{
		if (nullptr != mpShader)
		{
			auto item = mGSDataMaps.find(name);
			if (item != mGSDataMaps.end())
			{
				auto& pair = item->second;
				memcpy(std::get<1>(pair), pData, std::get<0>(pair));
			}
			else if (mpShader->mGeometryParamMap.find(name) != mpShader->mGeometryParamMap.end())
			{
				auto item = mpShader->mGeometryParamMap.find(name);
				if (item != mpShader->mGeometryParamMap.end())
				{
					auto& pair = item->second;
					int size = std::get<1>(pair);
					byte* pNewData = new byte[size];
					memcpy(pNewData, pData, size);
					mGSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, std::get<4>(pair));
				}
			}
		}
		return false;
	}

	bool CShaderUnit::addPSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addPSParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mPSDataMaps[name] = std::tuple<int, void*,int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addDSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addPSParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mDSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addHSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addPSParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mHSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addVSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addVSParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mVSDataMaps[nRegister] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addGSParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addGSParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mGSDataMaps[name] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addTextureConstBufferParam(const std::string& name, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addTextureConstBufferParam(name, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mTextureConstBufferMaps[nRegister] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return false;
	}

	bool CShaderUnit::addStructedBuffer(const std::string& name, INT32 structSize, INT32 size, INT32 nRegister, int offset)
	{
		if (nullptr != mpShader)
		{
			mpShader->addStructedBuffer(name, structSize, size, nRegister, offset);
			byte* pNewData = new byte[size];
			mStructBufferMaps[nRegister] = std::tuple<int, void*, int>(size, pNewData, offset);
		}
		return true;
	}

	void CShaderUnit::applyConstBuffer()
	{
		if (nullptr != mpShader)
		{
			updateVSConstBuffer(0, &mMatrix[0]);
			for( auto& item : mVSDataMaps )
			{
				auto& tuple = item.second;
				mpShader->updateVSConstBuffer(item.first,  std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mTextureConstBufferMaps)
			{
				auto& tuple = item.second;
				mpShader->updateTextureConstBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mTextureBufferMaps)
			{
				auto& tuple = item.second;
				mpShader->updateTextureBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mTypeBufferMaps)
			{
				auto& tuple = item.second;
				mpShader->updateTypeBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mStructBufferMaps)
			{
				auto& tuple = item.second;
				mpShader->updateStructedBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mHSDataMaps)
			{
				auto& tuple = item.second;
				mpShader->updateHSConstBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mDSDataMaps)
			{
				auto& tuple = item.second;
				mpShader->updateDSConstBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for( auto& item : mPSDataMaps )
			{
				auto& tuple = item.second;
				mpShader->updatePSConstBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
			for (auto& item : mGSDataMaps)
			{
				auto& tuple = item.second;
				mpShader->updateGSConstBuffer(item.first, std::get<1>(tuple), std::get<2>(tuple));
			}
		}
	}

	void CShaderUnit::setShader(DeviceContext* pDeviceContext)
	{
		if (nullptr != mpShader)
		{
			pDeviceContext->IASetPrimitiveTopology((D3D_PRIMITIVE_TOPOLOGY)mTopology);
			mpShader->use(pDeviceContext, 0);
		}
	}

	void CShaderUnit::setWorldMatrix(CMatrix* pMatrix)
	{
		D3DXMatrixTranspose(&mMatrix[0], pMatrix);
	}

	void CShaderUnit::setViewMatrix(CMatrix* pMatrix)
	{
		D3DXMatrixTranspose(&mMatrix[1], pMatrix);
	}

	void CShaderUnit::setProjectMatrix(CMatrix* pMatrix)
	{
		D3DXMatrixTranspose(&mMatrix[2], pMatrix);
	}

	void CShaderUnit::setOrthoMatrix(CMatrix* pMatrix)
	{
		D3DXMatrixTranspose(&mMatrix[2], pMatrix);
	}

	void CShaderUnit::setMatrix(MatrixType type, CMatrix* pMatrix)
	{
		if (MatrixType::WORLD == type)
		{
			setWorldMatrix(pMatrix);
		}
		else if (MatrixType::VIEW == type)
		{
			setViewMatrix(pMatrix);
		}
		else if (MatrixType::PROJECT == type)
		{
			setProjectMatrix(pMatrix);
		}

		else if (MatrixType::ORTHO == type)
		{
			setOrthoMatrix(pMatrix);
		}
	}

	void CShaderUnit::updateSpace()
	{

	}

	CShader* CShaderUnit::getShader() const
	{
		return mpShader;
	}

	void CShaderUnit::setTopology(UINT32 nTopology)
	{
		mTopology = nTopology;
	}


}